package com.atguigu.tingshu.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.user.*;
import com.atguigu.tingshu.user.mapper.*;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.joda.time.LocalDateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;
    @Resource
    private WxMaService wxMaService;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private RabbitService rabbitService;
    @Resource
    private UserPaidAlbumMapper userPaidAlbumMapper;
    @Resource
    private UserPaidTrackMapper userPaidTrackMapper;
    @Resource
    private TrackInfoFeignClient trackInfoFeignClient;
    @Resource
    private VipServiceConfigMapper vipServiceConfigMapper;
    @Resource
    private UserVipServiceMapper userVipServiceMapper;

    /**
     * 处理用户购买记录
     * @param userPaidRecordVo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void savePaidRecord(UserPaidRecordVo userPaidRecordVo) {
        //  记录用户购买信息;
        if (SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(userPaidRecordVo.getItemType())) {
            //  购买专辑 user_paid_album
            UserPaidAlbum userPaidAlbum = userPaidAlbumMapper.selectOne(new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getUserId, userPaidRecordVo.getUserId()).eq(UserPaidAlbum::getAlbumId, userPaidRecordVo.getItemIdList().get(0)));
            //  判断
            if (null != userPaidAlbum) {
                return;
            }
            //  创建对象保存数据：
            userPaidAlbum = new UserPaidAlbum();
            //  赋值：
            userPaidAlbum.setOrderNo(userPaidRecordVo.getOrderNo());
            userPaidAlbum.setUserId(userPaidRecordVo.getUserId());
            userPaidAlbum.setAlbumId(userPaidRecordVo.getItemIdList().get(0));
            //  保存数据;
            userPaidAlbumMapper.insert(userPaidAlbum);
        } else if (SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(userPaidRecordVo.getItemType())) {
            //  声音 user_paid_track; 判断当前购买的声音Id在当前表中是否存在！
            //  用户要购买的声音列表;
            List<Long> itemIdList = userPaidRecordVo.getItemIdList();
            //  用户已购买的声音列表;
            LambdaQueryWrapper<UserPaidTrack> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserPaidTrack::getUserId, userPaidRecordVo.getUserId())
                    .in(UserPaidTrack::getTrackId, itemIdList);
            //  用户在已购买的列表中买了对应的声音：
            List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(wrapper);
            //  需要将这个集合变为set集合; 通过trackId 判断是否存在;
            Set<Long> paidTrackIdSet = userPaidTrackList.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toSet());
            //  判断：
            if (!CollectionUtils.isEmpty(userPaidTrackList)) {
                //  有买过
                for (Long itemId : itemIdList) {
                    //  判断是否包含;
                    if (paidTrackIdSet.contains(itemId)) {
                        //  continue; break; return;
                        //  需要将包含的声音添加到集合中，用来记录哪些声音属于购买过!
                        //  需要使用mq进行增加余额;
                        continue;
                    }
                }
            }
            //  根据声音Id获取声音对象;
            Result<TrackInfo> trackInfoResult = trackInfoFeignClient.getTrackInfo(userPaidRecordVo.getItemIdList().get(0));
            Assert.notNull(trackInfoResult, "查询声音信息失败");
            TrackInfo trackInfo = trackInfoResult.getData();
            Assert.notNull(trackInfo, "查询声音信息失败");
            //  没有买过;
            for (Long trackId : itemIdList) {
                //  创建一个对象：
                UserPaidTrack userPaidTrack = new UserPaidTrack();
                userPaidTrack.setOrderNo(userPaidRecordVo.getOrderNo());
                userPaidTrack.setUserId(userPaidRecordVo.getUserId());
                userPaidTrack.setAlbumId(trackInfo.getAlbumId());
                userPaidTrack.setTrackId(trackId);
                //  保存数据;
                userPaidTrackMapper.insert(userPaidTrack);
            }
        } else {
            //  购买vip；user_vip_service - 可能需要续期；
            //  获取到购买时长;vip_service_config.id
            Long vipServiceId = userPaidRecordVo.getItemIdList().get(0);
            VipServiceConfig vipServiceConfig = vipServiceConfigMapper.selectById(vipServiceId);
            Integer serviceMonth = vipServiceConfig.getServiceMonth();
            //  保存数据：
            UserVipService userVipService = new UserVipService();
            //  赋值：
            userVipService.setOrderNo(userPaidRecordVo.getOrderNo());
            userVipService.setUserId(userPaidRecordVo.getUserId());
            Date currentTime = new Date();
            userVipService.setStartTime(currentTime);
            //  过期时间：稍后完成; 第一种情况：第一次购买；第二中情况：续期；
            //  判断当前用户是否是vip并且未过期，续期；
            UserInfo userInfo = userInfoMapper.selectById(userPaidRecordVo.getUserId());
            if (userInfo.getIsVip() == 1 && userInfo.getVipExpireTime().after(currentTime)) {
                //  属于续期；
                //  LocalDateTime localDateTime = new LocalDateTime(userInfo.getVipExpireTime());
                //                Date expireTime = localDateTime.plusMonths(serviceMonth).toDate();
                //                System.out.println("过期时间：" + expireTime);
                //                userVipService.setExpireTime(expireTime);
                currentTime = userInfo.getVipExpireTime();
            }
            //            else {
            //                //  第一次购买的vip的过期时间;;
            //                //  userVipService.setExpireTime(new LocalDateTime(new Date()).plusMonths(serviceMonth).toDate());
            //            }
            //  创建对象
            LocalDateTime localDateTime = new LocalDateTime(currentTime);
            //  获取过期时间
            Date expireTime = localDateTime.plusMonths(serviceMonth).toDate();
            //  设置过期时间
            userVipService.setExpireTime(expireTime);
            //  保存vip购买记录：
            userVipServiceMapper.insert(userVipService);
            //  修改用户的vip标识;
            userInfo.setIsVip(1);
            userInfo.setVipExpireTime(expireTime);
            this.updateById(userInfo);
        }
    }

    /**
     * 获取专辑已支付的声音Id集合列表
     * @param albumId
     * @param userId
     * @return
     */
    @Override
    public List<Long> findUserPaidTrackList(Long albumId, Long userId) {
        //  用户购买的声音列表在user_paid_track;
        List<Long> userPaidTrackList = userPaidTrackMapper.selectList(new LambdaQueryWrapper<UserPaidTrack>().eq(UserPaidTrack::getUserId, userId).
                        eq(UserPaidTrack::getAlbumId, albumId))
                .stream()
                .map(UserPaidTrack::getTrackId)
                .collect(Collectors.toList());
        //  用户购买的声音Id 列表；
        return userPaidTrackList;
    }

    /**
     * 判断用户是否购买过专辑
     *
     * @param userId
     * @param albumId
     * @return
     */
    @Override
    public Boolean isPaidAlbum(Long userId, Long albumId) {
        UserPaidAlbum userPaidAlbum = userPaidAlbumMapper.selectOne(new LambdaQueryWrapper<UserPaidAlbum>()
                .eq(UserPaidAlbum::getUserId, userId)
                .eq(UserPaidAlbum::getAlbumId, albumId));

        System.out.println("userPaidAlbum = " + userPaidAlbum);

        if (null != userPaidAlbum) {
            return true;
        }

        return false;
    }


    /**
     * 获取用户购买的声音
     *
     * @param albumId
     * @return
     */
    @Override
    public List<Integer> getUserPaidTrack(Long userId, Long albumId, List<Long> trackIdList) {
        //构建返回值
        List<Integer> list = new ArrayList<>();
        //判断用户是不是买过这个专辑,调用mapper
        UserPaidAlbum userPaidAlbum = userPaidAlbumMapper.selectOne(
                new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getUserId, userId)
                        .eq(UserPaidAlbum::getAlbumId, albumId)
        );
        //如果不是空的就说名购买了
        if (null != userPaidAlbum) {
            list.addAll(trackIdList.stream().map(Long::intValue).collect(Collectors.toList()));
            return list;
        }
        //如果为空就是没有买专辑，那就那就看看声音有没有买
        //查询用户购买的声音根据userid和albumid
        List<UserPaidTrack> userPaidTracks = userPaidTrackMapper.selectList(
                new LambdaQueryWrapper<UserPaidTrack>().eq(UserPaidTrack::getUserId, userId)
                        .in(UserPaidTrack::getTrackId, trackIdList)
        );
        //如果不为空就说名买了专辑里的声音
        if (null != userPaidTracks) {
            //封装返回值
            list.addAll(userPaidTracks.stream()
                    .map(UserPaidTrack::getTrackId).collect(Collectors.toList())
                    .stream().map(Long::intValue).collect(Collectors.toList()));

            return list;
        }
        //如果都没有就返回空的list
        return list;
    }

    /**
     * 修改用户id
     *
     * @param userId
     * @param userInfoVo
     */
    @Override
    public void updateUser(Long userId, UserInfoVo userInfoVo) {
        //获取用户的原信息
        UserInfo userInfo = userInfoMapper.selectById(userId);
        //信息拷贝
        BeanUtils.copyProperties(userInfoVo, userInfo);
        userInfo.setId(userId);
        //更新用户信息
        userInfoMapper.updateById(userInfo);
    }

    /**
     * 获取用户信息
     *
     * @param userId
     * @return
     */
    @Override
    public UserInfoVo getUserInfo(Long userId) {
        //封装返回值
        UserInfoVo userInfoVo = new UserInfoVo();
        //根据id获取用户信息
        UserInfo userInfo = userInfoMapper.selectById(userId);
        //信息拷贝
        BeanUtils.copyProperties(userInfo, userInfoVo);
        //返回结果
        return userInfoVo;
    }

    /**
     * 微信登录
     *
     * @param code
     * @return
     */
    @Override
    public HashMap<String, Object> wxLogin(String code) {
        //调用微信的api获得OpenID
        WxMaJscode2SessionResult wxMaJscode2SessionResult = null;
        try {
            wxMaJscode2SessionResult = wxMaService.jsCode2SessionInfo(code);
        } catch (WxErrorException e) {
            throw new RuntimeException(e);
        }
        String openid = wxMaJscode2SessionResult.getOpenid();

        //根据openid去数据库中查询，如果查到了，就把token保存到redis中，如果没有就注册
        UserInfo userInfo = userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getWxOpenId, openid));
        //判断是不是空的
        if (null == userInfo) {
            //空的就去注册,就是给userinfo赋值wx_open_id，nickname，avatar_url
            UserInfo userInfo1 = new UserInfo();
            userInfo1.setWxOpenId(openid);
            userInfo1.setNickname("不是哥们" + UUID.randomUUID().toString().replaceAll("-", ""));
            userInfo1.setAvatarUrl("https://ts3.tc.mm.bing.net/th/id/ODF.T0iTu20w8jwu9conMCwNGw?w=32&h=32&qlt=90&pcl=fffffc&o=6&pid=1.2");
            //发送异步消息进行初始化的东西
            rabbitService.sendMessage(MqConst.EXCHANGE_USER, MqConst.ROUTING_USER_REGISTER, userInfo.getId());
            //保存用户信息
            userInfoMapper.insert(userInfo1);
        }

        //登录，这个不用if
        //生成token，把用户数据存进去
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        //组成redis的key
        String redisKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;

        //保存数据
        redisTemplate.opsForValue().set(redisKey, userInfo, RedisConstant.USER_LOGIN_REFRESH_KEY_TIMEOUT, TimeUnit.SECONDS);
        //封装返回值
        HashMap<String, Object> resultMap = new HashMap<>();
        //放数据
        resultMap.put("token", token);
        //返回数据
        return resultMap;
    }
}
